package com.yict.common.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;
import org.springside.modules.utils.ReflectionUtils;

import com.yict.common.entity.PageEntity;

/**
 * 基础存储类
 * 
 * @author tortoi.huang
 * 
 * @param <T>
 * @param <PK>
 */
// @Repository("baseDao")
public class BaseDao<T, PK extends Serializable> extends HibernateDaoSupport {
	private static Log logger = LogFactory.getLog(BaseDao.class);

	private Class<T> entity;
	private PageEntity pageEntity;

	public HibernateTemplate getTemplate() {
		return this.getHibernateTemplate();
	}

	/**
	 * 分页查询
	 * 
	 * @param valueMap
	 * @param page
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> search(Map<String, Object> valueMap, PageEntity page) {
		List<T> list = new ArrayList<T>();
		pageEntity = new PageEntity();
		String queryString = this.buildHql(valueMap, null);
		try {
			int count = this.queryCount(valueMap);
			if (queryString != null && !"".equals(queryString) && count > 0) {
				Query query = this.getSession().createQuery(queryString);
				if (valueMap != null && valueMap.size() > 0) {
					Set<Map.Entry<String, Object>> entrys = valueMap.entrySet();
					for (Map.Entry<String, Object> entry : entrys) {
						String key = entry.getKey();
						Object value = entry.getValue();
						if (value instanceof Object[] && value != null) {
							Object[] os = (Object[]) value;
							query.setParameterList(key, os);
						} else if (value instanceof Collection && value != null) {
							Collection<Object> os = (Collection<Object>) value;
							query.setParameterList(key, os);
						} else if (value != null && !"".equals(value)) {
							query.setParameter(key, value);
						}

					}
				}
				if (page != null) {
					pageEntity.setTotalRecord(count);
					if (page.getStartNm() > 0) {
						query.setFirstResult(page.getStartNm());
					}
					if (page.getPageSize() > 0) {
						query.setMaxResults(page.getPageSize());
					}
				}
				list = query.list();
			}
		} catch (Exception e) {
			logger.error(e);
		}
		return list;
	}

	/**
	 * 排序分页查询
	 * 
	 * @param valueMap
	 * @param orderList
	 *            key为排序列名称，value为true则正序，否则倒序查询
	 * @param rowFrom
	 * @param rowSize
	 * @return
	 */
	public List<T> list(Map<String, Object> valueMap,
			final LinkedHashMap<String, Boolean> orderList, final int rowFrom,
			final int rowSize) {
		final String queryString = this.buildHql(valueMap, orderList);
		return this.list(queryString, valueMap, rowFrom, rowSize);
	}

	/**
	 * 排序分页查询
	 * 
	 * @param queryString
	 * @param valueMap
	 * @param orderList
	 *            key为排序列名称，value为true则正序，否则倒序查询
	 * @param rowFrom
	 * @param rowSize
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> list(final String queryString,
			final Map<String, Object> valueMap, final int rowFrom,
			final int rowSize) {
		List<T> list = new ArrayList<T>();
		try {
			if (queryString != null && !"".equals(queryString)) {
				list = (List<T>) this.getHibernateTemplate().execute(
						new HibernateCallback() {

							@Override
							public Object doInHibernate(Session session)
									throws HibernateException, SQLException {
								Query query = session.createQuery(queryString);
								if (valueMap != null && valueMap.size() > 0) {
									Set<Map.Entry<String, Object>> entrys = valueMap
											.entrySet();
									for (Map.Entry<String, Object> entry : entrys) {
										String key = entry.getKey().replaceAll("\\.", "_");
										Object value = entry.getValue();
										if (value instanceof Object[]
												&& value != null) {
											Object[] os = (Object[]) value;
											query.setParameterList(key, os);
										} else if (value instanceof Collection
												&& value != null) {
											Collection<Object> os = (Collection<Object>) value;
											query.setParameterList(key, os);
										} else if (value != null
												&& !"".equals(value)) {
											query.setParameter(key, value);
										}
									}
								}
								if (rowFrom > 0) {
									query.setFirstResult(rowFrom);
								}
								if (rowSize > 0) {
									query.setMaxResults(rowSize);
								}
								return query.list();
							}
						});
			}
		} catch (Exception e) {
			logger.error(e);
		}
		return list;
	}
	
	/**
	 * 本地sql排序分页查询
	 * 
	 * @param queryString
	 * @param valueMap
	 * @param orderList
	 *            key为排序列名称，value为true则正序，否则倒序查询
	 * @param rowFrom
	 * @param rowSize
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> listSql(final String queryString,
			final Map<String, Object> valueMap, final int rowFrom,
			final int rowSize) {
		List<T> list = new ArrayList<T>();
		try {
			if (queryString != null && !"".equals(queryString)) {
				list = (List<T>) this.getHibernateTemplate().execute(
						new HibernateCallback() {
							
							@Override
							public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
								Query query = session.createSQLQuery(queryString).addEntity(entity);
								if (valueMap != null && valueMap.size() > 0) {
									Set<Map.Entry<String, Object>> entrys = valueMap
									.entrySet();
									for (Map.Entry<String, Object> entry : entrys) {
										String key = entry.getKey();
										Object value = entry.getValue();
										if (value instanceof Object[]
										                            && value != null) {
											Object[] os = (Object[]) value;
											query.setParameterList(key, os);
										} else if (value instanceof Collection
												&& value != null) {
											Collection<Object> os = (Collection<Object>) value;
											query.setParameterList(key, os);
										} else if (value != null
												&& !"".equals(value)) {
											query.setParameter(key, value);
										}
									}
								}
								if (rowFrom > 0) {
									query.setFirstResult(rowFrom);
								}
								if (rowSize > 0) {
									query.setMaxResults(rowSize);
								}
								return query.list();
							}
						});
			}
		} catch (Exception e) {
			logger.error(e);
		}
		return list;
	}

	/**
	 * 根据条件查询记录
	 * 
	 * @param valueMap
	 *            所有条件做等于查询
	 * @return
	 */
	public int queryCount(Map<String, Object> valueMap) {
		final String queryString = "select count(*) "
				+ this.buildHql(valueMap, null);
		return this.queryCount(queryString, valueMap);
	}

	/**
	 * 查询总记录数
	 * 
	 * @param queryString
	 * @param valueMap
	 * @return
	 */
	public int queryCount(final String queryString, final Map<String, Object> valueMap) {
		int count = 0;
		Object obj = this.getHibernateTemplate().execute(
				new HibernateCallback() {

					@Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(queryString);
						if (valueMap != null
								&& valueMap.size() > 0) {
							Set<Map.Entry<String, Object>> entrys = valueMap
									.entrySet();
							for (Map.Entry<String, Object> entry : entrys) {
								String key = entry.getKey().replaceAll("\\.", "_");
								Object value = entry.getValue();
								if (value instanceof Object[] && value != null) {
									Object[] os = (Object[]) value;
									query.setParameterList(key, os);
								} else if (value instanceof Collection
										&& value != null) {
									@SuppressWarnings("unchecked")
									Collection<Object> os = (Collection<Object>) value;
									query.setParameterList(key, os);
								} else if (value != null && !"".equals(value)) {
									query.setParameter(key, value);
								}
							}
						}
						return query.uniqueResult();
					}
				});
		if(obj != null)
			count = ((Number) obj).intValue();
		return count;
	}

	/**
	 * 查询列表
	 * 
	 * @param queryString
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("unchecked")
	public List<T> find(String queryString) {
		List<T> list = new ArrayList<T>();
		try {
			list = this.getTemplate().find(queryString);
		} catch (Exception e) {
			logger.error(e);
		}
		return list;
	}

	/**
	 * 根据主键查询记录
	 * 
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T findbyId(PK id) {
		T t = null;
		try {
			Object obj = this.getTemplate().get(entity, id);
			t = (T) obj;
		} catch (Exception e) {
			logger.error(e);
		}
		return t;
	}

	/**
	 * 添加记录
	 * 
	 * @param t
	 * @return
	 * @throws Exception
	 */
	public boolean save(T t) throws Exception {
		Assert.notNull(t);
		boolean bool = false;
		try {
			this.getTemplate().save(t);
			bool = true;
		} catch (Exception e) {
			logger.error(e);
		}
		return bool;
	}
	
	public boolean save(List<T> t) throws Exception {
		Assert.notNull(t);
		boolean bool = false;
		try {
			this.getTemplate().saveOrUpdateAll(t);
			bool = true;
		} catch (Exception e) {
			logger.error(e);
		}
		return bool;
	}

	/**
	 * 更新记录
	 * 
	 * @param t
	 * @return
	 * @throws Exception
	 */
	public boolean update(T t) throws Exception {
		Assert.notNull(t);
		boolean bool = false;
		try {
			this.getTemplate().merge(t);
			bool = true;
		} catch (Exception e) {
			logger.error(e);
		}
		return bool;
	}

	/**
	 * 删除记录
	 * 
	 * @param t
	 * @return
	 * @throws Exception
	 */
	public boolean remove(T t) throws Exception {
		boolean bool = false;
		try {
			this.getTemplate().delete(t);
			bool = true;
		} catch (Exception e) {
			logger.error(e);
		}
		return bool;
	}

	public boolean remove(List<T> list) throws Exception {
		boolean bool = false;
		try {
			this.getTemplate().deleteAll(list);
			bool = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bool;
	}
	
	/**
	 * 
	 * @param ids
	 * @return
	 * @throws Exception
	 */
	public boolean remove(final PK[] ids) throws Exception {
		if(ids == null || ids.length == 0) 
			return true;
		List<PK> idlist = new ArrayList<PK>();
		for (PK id : ids)
			idlist.add(id);
		return remove(idlist);
	}

	/**
	 * 
	 * @param ids
	 * @return
	 * @throws Exception
	 */
	public boolean remove(final Collection<PK> ids) throws Exception {
		if(ids == null || ids.size() == 0) 
			return true;
		boolean bool = false;
		try {
			ClassMetadata meta = super.getSessionFactory().getClassMetadata(
					entity);
			String idName = meta.getIdentifierPropertyName();
			final String hql = "delete from " + entity.getName() + " t where "
					+ idName + " in (:ids)";
			this.getHibernateTemplate().execute(new HibernateCallback() {

				@Override
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query query = session.createQuery(hql);
					query.setParameterList("ids", ids);
					return query.executeUpdate();
				}
			});
			bool = true;
		} catch (Exception e) {
			logger.error(e);
		}
		return bool;
	}

	/**
	 * 获取数据库时间
	 * 
	 * @return
	 */
	public Date queryDbTimeStamp() {
		Date date;
		final String hql = "SELECT CURRENT_TIMESTAMP() from "
				+ entity.getName() + " t";
		Object obj = this.getHibernateTemplate().execute(
				new HibernateCallback() {

					@Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						query.setFirstResult(0);
						query.setMaxResults(1);
						return query.uniqueResult();
					}
				});
		date = (Date) obj;
		return date;
	}

	/**
	 * 构建查询语句
	 * 
	 * @param map
	 * @param orderList
	 * @return
	 */
	private String buildHql(Map<String, Object> map,
			LinkedHashMap<String, Boolean> orderList) {
		StringBuilder  hql = new StringBuilder("from ");
		hql.append(" ").append(entity.getName()).append(" t where 1 = 1 ");
		
		/*List<String> propertys = new ArrayList<String>();
		Field[] fields = entity.getDeclaredFields();
		for(Field f : fields){
			if(f.getAnnotation(javax.persistence.Column.class) != null){
				propertys.add(f.getName());
			}
		}*/
		if(map != null && map.size() >0) {
			for (Map.Entry<String, Object> entry : map.entrySet()) {
				String s = entry.getKey();
				Object key = entry.getValue();
				if(key == null)
					hql.append(" and t.").append(s).append(" is null");
				else if(key instanceof Object[] || key instanceof Collection)
					hql.append(" and t.").append(s).append(" in (:").append(s.replaceAll("\\.", "_")).append(") ");
				else 
					hql.append(" and t.").append(s).append("=:").append(s.replaceAll("\\.", "_")).append(" ");
			}
		}
		
		if(orderList != null && orderList.size() > 0){
			hql.append(" order by ");
			int i = 0;
			for(Map.Entry<String, Boolean> entry : orderList.entrySet()){
				if(i > 0) hql.append(",");
				hql.append("t.").append(entry.getKey());
				if(!entry.getValue()) hql.append(" desc"); 
				i++;
			}
		}
		
		
		return hql.toString();
	}

	public PageEntity getPageEntity() {
		return pageEntity;
	}

	public void setPageEntity(PageEntity pageEntity) {
		this.pageEntity = pageEntity;
	}

	public Class<T> getEntity() {
		return entity;
	}

	public void setEntity(Class<T> entity) {
		this.entity = entity;
	}
	
	@PostConstruct
	public void setEntity() {
		this.entity = ReflectionUtils.getSuperClassGenricType(getClass());
	}
}
